package RabbitMQ

import (
	"fmt"
	"log"
)

const MQURL = "amqp://cuser:cuser@127.0.0.1:5672/test"

type RabbitMQ struct {
	conn *amqp.Connection
	channel *amqp.Channel
	//队列名称
	QueueName string
	//交换机
	Exchange string
	//key
	Key string
	//连接信息
	Mqurl string
}

//step:1 创建简单模式下RabbitMQ实例
func NewRabbitMQSimple(queueName string) *RabbitMQ {
	return NewRabbitMQ(queueName, "", "")
}

//step:2 简单模式下生产示例代码
func (r *RabbitMQ) PublishSimple(message string) {
	//1.申请队列（如队列不存在则创建，存在则跳过）
	//保证队列存在，消息能发送到队列中
	_ , err := r.channel.QueueDeclare(
		r.QueueName,
		//是否持久化
		false,
		//是否为自动删除
		false,    //autoDelete
		//是否具有排他性
		false,    //exclusive
		//是否阻塞
		false,    //noWait
		//额外属性
		nil,
	)

	if err != nil {
		fmt.Println(err)
	}

	//2.发送消息到队列中
	r.channel.Publish(
		r.Exchange,
		r.QueueName,
		//如果为 true，根据 exchange 类型和 routkey 规则，如果无法找到符合条件的队列，那么会把发送的消息返还给发送者
		false,    //mandatory
		//如果为 true，当 exchange 发送消息到队列后发现队列上没有绑定消费者，则会把消息返还给发送者
		false,    //immediate
		amqp.Publishing {
			ContentType:"text/plain",
			Body:[]byte(message),
		},
	)
}

//简单模式下消费示例代码
func (r *RabbitMQ) ConsumeSimple() {
		//1.申请队列（如队列不存在则创建，存在则跳过）
		//保证队列存在，消息能发送到队列中
		_ , err := r.channel.QueueDeclare(
			r.QueueName,
			//是否持久化
			false,
			//是否为自动删除
			false,    //autoDelete
			//是否具有排他性
			false,    //exclusive
			//是否阻塞
			false,    //noWait
			//额外属性
			nil,
		)

		if err != nil {
			fmt.Println(err)
		}

		//2.接受消息
		msgs,err := r.channel.Consume(
			r.QueueName,
			//用来区分多个消费者
			"",    //consumer
			//是否自动应答
			true,    //autoAck
			//是否具有排他性
			false,    //exclusive
			//如果设置为 true，表示不能将同一个 connection 中发送的消息传递给这个 connection 中的消费者
			false,    //noLocal
			//队列消费是否阻塞
			false,    //noWait
			nill,    //args
		)

		if err != nil {
			fmt.Println(err)
		}

		forever := make(chan bool)
		//3.启用协程处理消息
		go func() {
			for d := range msgs {
				//实现我们要处理的逻辑函数
				log.Printf("Received a message: %s", d.Body)
			}
		}()

		log.Printf("[*] Waiting for messages, To exit press CTRL + C")
		//阻塞
		<-forever
}

//创建RabbitMQ结构体实例
func NewRabbitMQ(queueName string, exchange string, key string) * RabbitMQ {
    rabbitmq := &RabbitMQ{QueueName: queueName, Exchange: exchange, Key: key, Mqurl: MQURL}

	//创建 rabbitmq 连接
	rabbitmq.conn,err = amqp.Dial(rabbitmq.Mqurl)
	rabbitmq.failOnErr(err, "创建连接错误！")
	rabbitmq.channel,err = rabbitmq.conn.Channel()
	rabbitmq.failOnErr(err,"获取channel失败")

    return rabbitmq
}

//断开 channel 和 connection
func (r *RabbitMQ) Destory() {
	r.channel.Close()
	r.conn.Close()
}

//错误处理函数
func (r *RabbitMQ) failOnErr(err error, message string) {
	if err != nil {
		log.Fatalf("%s:%s", message, err)
		panic(fmt.Sprintf("%s:%s", message, err))
	}
}
